﻿using Quartz;
using Quartz.Impl;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Pit.Application.Scheduler
{
    public class JobPoolManager : IDisposable
    {
        private static ConcurrentDictionary<long, JobRuntimeInfo> JobRuntimePool =
            new ConcurrentDictionary<long, JobRuntimeInfo>();

        private static IScheduler _scheduler;
        private static JobPoolManager _jobPollManager;

        private JobPoolManager() { }

        static JobPoolManager()
        {
            _jobPollManager = new JobPoolManager();
            _scheduler = (IScheduler)StdSchedulerFactory.GetDefaultScheduler();
            _scheduler.Start();
        }

        public static JobPoolManager Instance
        {
            get { return _jobPollManager; }

        }

        static object _lock = new object();
        public bool Add(long jobId, JobRuntimeInfo jobRuntimeInfo)
        {
            lock (_lock)
            {
                if (!JobRuntimePool.ContainsKey(jobId))
                {
                    if (JobRuntimePool.TryAdd(jobId, jobRuntimeInfo))
                    {
                        IDictionary<string, object> data = new Dictionary<string, object>()
                        {
                            ["JobId"] = jobId
                        };
                        IJobDetail jobDetail = JobBuilder.Create<JobImplement>()
                            .WithIdentity(jobRuntimeInfo.JobModel.JobName, jobRuntimeInfo.JobModel.Group)
                            .SetJobData(new JobDataMap(data))
                            .Build();
                        var tiggerBuilder = TriggerBuilder.Create()
                            .WithIdentity(jobRuntimeInfo.JobModel.JobName, jobRuntimeInfo.JobModel.Group);
                        if (string.IsNullOrWhiteSpace(jobRuntimeInfo.JobModel.TaskCron))
                        {
                            tiggerBuilder = tiggerBuilder.WithSimpleSchedule((simple) =>
                            {
                                simple.WithInterval(TimeSpan.FromSeconds(1));
                            });
                        }
                        else
                        {
                            tiggerBuilder = tiggerBuilder
                                .StartNow()
                                .WithCronSchedule(jobRuntimeInfo.JobModel.TaskCron);
                        }
                        var trigger = tiggerBuilder.Build();
                        _scheduler.ScheduleJob(jobDetail, trigger);
                        return true;
                    }
                }
                return false;
            }
        }

        public JobRuntimeInfo Get(long jobId)
        {
            if (!JobRuntimePool.ContainsKey(jobId))
            {
                return null;
            }
            lock (_lock)
            {
                if (JobRuntimePool.ContainsKey(jobId))
                {
                    JobRuntimeInfo jobRuntimeInfo = null;
                    JobRuntimePool.TryGetValue(jobId, out jobRuntimeInfo);
                    return jobRuntimeInfo;
                }
                return null;
            }
        }

        public bool Remove(long jobId)
        {
            lock (_lock)
            {
                if (JobRuntimePool.ContainsKey(jobId))
                {
                    JobRuntimeInfo jobRuntimeInfo = null;
                    JobRuntimePool.TryGetValue(jobId, out jobRuntimeInfo);
                    if (jobRuntimeInfo != null)
                    {
                        var tiggerKey = new TriggerKey(jobRuntimeInfo.JobModel.JobName,
                            jobRuntimeInfo.JobModel.Group);
                        _scheduler.PauseTrigger(tiggerKey);

                        _scheduler.UnscheduleJob(tiggerKey);

                        _scheduler.DeleteJob(new JobKey(jobRuntimeInfo.JobModel.JobName,
                            jobRuntimeInfo.JobModel.Group));

                        JobRuntimePool.TryRemove(jobId, out jobRuntimeInfo);

                        return true;
                    }
                }
                return false;
            }
        }

        public virtual void Dispose()
        {
            if (_scheduler != null && !_scheduler.IsShutdown)
            {
                //foreach (var jobId in JobRuntimePool.Keys)
                //{
                //    var jobState = ConnectionFactory.GetInstance<Job.Provider.JobStateRepository>().Get(jobId);
                //    if (jobState != null)
                //    {
                //        jobState.RunState = (int)DirectiveType.Stop;
                //        jobState.UpdateTime = DateTime.Now;
                //        ConnectionFactory.GetInstance<Job.Provider.JobStateRepository>().Update(jobState);
                //    }
                //}
                //_scheduler.Shutdown();
            }
        }
    }
}
